﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Data.SqlClient;

namespace YTSK.Ext
{
    internal  class ExpressionResolve
    {
        public string DealExpress(Expression exp, out List<SqlParameter> ps)
        {
            index = 0;
            paras = new List<SqlParameter>();
            var sval = DealExpress(exp);
            ps = paras;
            return sval;
        }
        private int index;
        private List<SqlParameter> paras;
        private string DealExpress(Expression exp)
        {

            if (exp is LambdaExpression)
            {
                LambdaExpression l_exp = exp as LambdaExpression;
                var s1 = DealExpress(l_exp.Body);
                return s1;
            }
            if (exp is BinaryExpression)
            {
                var s2 = DealBinaryExpression(exp as BinaryExpression);
                return s2;
            }
            if (exp is MemberExpression)
            {
                var s3 = DealMemberExpression(exp as MemberExpression);
                return s3.ToString();
            }
            if (exp is ConstantExpression)
            {
                var s4 = DealConstantExpression(exp as ConstantExpression);
                return s4;
            }
            if (exp is UnaryExpression)
            {
                var s5 = DealUnaryExpression(exp as UnaryExpression);
                return s5;
            }
            return "";
        }

        #region 一元符号，暂时不支持
        private string DealUnaryExpression(UnaryExpression exp)
        {
            return DealExpress(exp.Operand);
        }
        #endregion

        #region 值处理
        private string DealConstantExpression(ConstantExpression exp)
        {
            object value = exp.Value;
            string v_str = string.Empty;
            if (value == null || value == DBNull.Value)
            {
                return "NULL";
            }
            var para = new SqlParameter("@p" + index.ToString(), value);
            paras.Add(para);
            v_str = "@p" + index.ToString();
            index++;
            return v_str;
        }

        private string DealConstantExpression(object value)
        {
            string v_str = string.Empty;
            if (value == null || value == DBNull.Value)
            {
                return "NULL";
            }
            var para = new SqlParameter("@p" + index.ToString(), value);
            paras.Add(para);
            v_str = "@p" + index.ToString();
            index++;
            return v_str;
        }
        #endregion

        #region 拆分条件表达式
        private string DealBinaryExpression(BinaryExpression exp)
        {
            string left;
            if (exp.Left is BinaryExpression && (exp.Left as BinaryExpression).Left is BinaryExpression)
            { left = "(" + DealExpress(exp.Left) + ")"; }
            else
            { left = DealExpress(exp.Left); }
            string oper = GetOperStr(exp.NodeType);
            string right;
            if (exp.Right is BinaryExpression && (exp.Right as BinaryExpression).Left is BinaryExpression)
            {
                right = "(" + DealExpress(exp.Right) + ")";
            }
            else { right = DealExpress(exp.Right); }
            if (right == "NULL")
            {
                if (oper == "=")
                {
                    oper = " is ";
                }
                else
                {
                    oper = " is not ";
                }
            }
            return left + oper + right;
        }
        #endregion


        #region 条件列名
        private object DealMemberExpression(MemberExpression exp)
        {
            switch (exp.Expression.NodeType)
            {
                case ExpressionType.Constant:
                    var bb = exp.Expression as ConstantExpression;
                    var val= DealMemberExpression_Constand(bb, exp.Member.Name);
                    return DealConstantExpression(val);
                case ExpressionType.MemberAccess:
                    var val1= Expression.Lambda(exp).Compile().DynamicInvoke();
                    return DealConstantExpression(val1);

                //case ExpressionType.Parameter:
                //    var tmp = exp.Expression as ParameterExpression;
                //    return DealMemberExpression_Parameter(tmp,exp, exp.Member.Name);
                case ExpressionType.Parameter:
                default:
                    return exp.Member.Name;

            }
        }

        private string DealMemberExpression_Constand(ConstantExpression conexp, string filename)
        {
            var value = conexp.Value;
            var field = value.GetType().GetField(filename);
            return field.GetValue(value).ObjToString();
        }
        private object DealMemberExpression_Parameter(MemberExpression exp, string filename)
        {
            var memberAccess = exp.Expression as MemberExpression;
            if (memberAccess.Expression == null)
            {
                memberAccess = Expression.MakeMemberAccess(null, memberAccess.Member);
            }
            else
            {
                var member = exp.Type.GetMember(memberAccess.Member.Name).FirstOrDefault();
                memberAccess = Expression.MakeMemberAccess(exp, member);
            }
            return memberAccess;
        }


        #endregion

        #region 符号处理
        private string GetOperStr(ExpressionType e_type)
        {
            switch (e_type)
            {
                case ExpressionType.OrElse: return " OR ";
                case ExpressionType.Or: return "|";
                case ExpressionType.AndAlso: return " AND ";
                case ExpressionType.And: return " AND ";
                case ExpressionType.GreaterThan: return ">";
                case ExpressionType.GreaterThanOrEqual: return ">=";
                case ExpressionType.LessThan: return "<";
                case ExpressionType.LessThanOrEqual: return "<=";
                case ExpressionType.NotEqual: return "<>";
                case ExpressionType.Add: return "+";
                case ExpressionType.Subtract: return "-";
                case ExpressionType.Multiply: return "*";
                case ExpressionType.Divide: return "/";
                case ExpressionType.Modulo: return "%";
                case ExpressionType.Equal: return "=";
            }
            return "";
        }
        #endregion
    }
}
